#ifndef _FIFO_H_
#define _FIFO_H_

#include <mutex>

template <typename T>
class FIFO
{
public:
    typedef struct node_s
    {
        T data;
        struct node_s *next;
    } node_t;

public:
    FIFO()
    {
    }
    ~FIFO()
    {
        delete[] m_data;
    }
    void init(int maxcount)
    {
        m_data = new node_t[maxcount];
        memset(m_data, 0, sizeof(node_t) * maxcount);
        m_head = m_data;
        m_tail = m_data;
        m_maxCount = maxcount;
        m_count = 0;
        for (int i = 0; i < maxcount - 1; i++)
        {
            m_data[i].next = &m_data[i + 1];
        }
        m_data[maxcount - 1].next = &m_data[0];
    }
    int count()
    {
        std::lock_guard<std::mutex> Lock(m_mtx);
        return m_count;
    }
    int isEmpty()
    {
        std::lock_guard<std::mutex> Lock(m_mtx);
        return m_count == 0;
    }
    int read(T *data, int count)
    {
        std::lock_guard<std::mutex> Lock(m_mtx);
        if (count > m_count)
        {
            return 0;
        }
        else
        {
            for (int i = 0; i < count; i++)
            {
                data[i] = m_head->data;
                m_head = m_head->next;
            }
            m_count -= count;
            return count;
        }
    }
    int write(T *data, int count)
    {
        std::lock_guard<std::mutex> Lock(m_mtx);
        if (count > m_maxCount - m_count)
        {
            return 0;
        }
        else
        {
            for (int i = 0; i < count; i++)
            {
                m_tail->data = data[i];
                m_tail = m_tail->next;
            }
            m_count += count;
            return count;
        }
    }

private:
    node_t *m_data;
    node_t *m_head;
    node_t *m_tail;
    int m_count;
    int m_maxCount;
    std::mutex m_mtx;
};
#endif